using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using MQTTnet.Server;

namespace HslCommunicationEx.Mqtt
{
	public class MqttNetServer
	{
		public MqttServer Server = null;

		public Dictionary<string, string> _dicUser = new Dictionary<string, string>();

		private MqttNetLogger _logger;

		public List<ClientConnectedEventArgs> ClientOnlineList = new List<ClientConnectedEventArgs>();

		public bool IsAuthorize { get; set; } = true;


		public Action<EventArgs> ActOnMqttServerStarted { get; set; }

		public Action<EventArgs> ActOnMqttServerStopped { get; set; }

		public Action<ClientConnectedEventArgs> ActOnMqttServerClientConnected { get; set; }

		public Action<ClientDisconnectedEventArgs> ActOnMqttClientDisconnected { get; set; }

		public Action<ClientSubscribedTopicEventArgs> ActClientSubscribedTopicAsync { get; set; }

		public Action<ClientUnsubscribedTopicEventArgs> ActClientUnsubscribedTopicAsync { get; set; }

		public Action<MqttApplicationMessageReceivedEventArgs> ActOnMqttServerApplicationMessageReceived { get; set; }

		public Action<Exception> ErrorHandler { get; set; }

		public MqttNetLogger Logger => this._logger;

		public async void StartMqttServer(int port, string userName, string pwd)
		{
			try
			{
				if (this.Server != null)
				{
					return;
				}
				this._logger = new MqttNetLogger();
				MqttFactory mqttFactory = new MqttFactory(this._logger);
				MqttServerOptions mqttServerOptions = new MqttServerOptionsBuilder().WithDefaultEndpoint().WithDefaultEndpointPort(port).Build();
				if (this.IsAuthorize)
				{
					this.AddUser(userName, pwd);
				}
				this.Server = mqttFactory.CreateMqttServer(mqttServerOptions);
				this.Server.ValidatingConnectionAsync += delegate(ValidatingConnectionEventArgs e)
				{
					if (e.UserName != userName)
					{
						e.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
					}
					if (e.Password != pwd)
					{
						e.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
					}
					e.ReasonCode = MqttConnectReasonCode.Success;
					return Task.CompletedTask;
				};
				this.Server.StartedAsync += OnMqttServerStarted;
				this.Server.StoppedAsync += OnMqttServerStopped;
				this.Server.ClientConnectedAsync += OnMqttServerClientConnected;
				this.Server.ClientDisconnectedAsync += OnMqttClientDisconnected;
				this.Server.ClientSubscribedTopicAsync += OnClientSubscribedTopicAsync;
				this.Server.ClientUnsubscribedTopicAsync += OnClientUnsubscribedTopicAsync;
				await this.Server.StartAsync();
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				throw new Exception("start server failed!", ex);
			}
		}

		public async Task StopMqttServer()
		{
			if (this.Server != null)
			{
				await this.Server.StopAsync();
				this.Server = null;
			}
		}

		public void AddUser(string userName, string pwd)
		{
			if (!string.IsNullOrWhiteSpace(userName) && !string.IsNullOrWhiteSpace(pwd))
			{
				if (!this._dicUser.ContainsKey(userName))
				{
					this._dicUser.Add(userName, pwd);
				}
				else
				{
					this._dicUser[userName] = pwd;
				}
			}
		}

		public void RemoveUser(string userName)
		{
			if (this._dicUser.ContainsKey(userName))
			{
				this._dicUser.Remove(userName);
			}
		}

		public virtual Task OnMqttServerStarted(EventArgs e)
		{
			try
			{
				this.ActOnMqttServerStarted?.Invoke(e);
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}

		public Task OnMqttServerStopped(EventArgs e)
		{
			try
			{
				this.ActOnMqttServerStopped?.Invoke(e);
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}

		public Task OnMqttServerClientConnected(ClientConnectedEventArgs e)
		{
			if (this.ClientOnlineList.All((ClientConnectedEventArgs x) => x.ClientId != e.ClientId))
			{
				this.ClientOnlineList.Add(e);
			}
			MqttApplicationMessage applicationMessage = new MqttApplicationMessageBuilder().WithTopic(e.ClientId + ":ConnectState").WithPayload(new byte[1] { 1 }).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
				.WithRetainFlag()
				.Build();
			this.Server.InjectApplicationMessage(new InjectedMqttApplicationMessage(applicationMessage));
			this.ActOnMqttServerClientConnected?.Invoke(e);
			return Task.CompletedTask;
		}

		public Task OnMqttClientDisconnected(ClientDisconnectedEventArgs e)
		{
			try
			{
				this.ClientOnlineList.RemoveAll((ClientConnectedEventArgs x) => x.ClientId == e.ClientId);
				MqttApplicationMessage applicationMessage = new MqttApplicationMessageBuilder().WithTopic(e.ClientId + ":ConnectState").WithPayload(new byte[1]).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
					.WithRetainFlag()
					.Build();
				if (this.Server?.IsStarted ?? false)
				{
					this.Server.InjectApplicationMessage(new InjectedMqttApplicationMessage(applicationMessage));
				}
				this.ActOnMqttClientDisconnected?.Invoke(e);
				return Task.CompletedTask;
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}

		public Task OnClientSubscribedTopicAsync(ClientSubscribedTopicEventArgs e)
		{
			try
			{
				this.ActClientSubscribedTopicAsync?.Invoke(e);
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}

		public Task OnClientUnsubscribedTopicAsync(ClientUnsubscribedTopicEventArgs e)
		{
			try
			{
				this.ActClientUnsubscribedTopicAsync?.Invoke(e);
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}

		public Task OnMqttServer_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
		{
			try
			{
				this.ActOnMqttServerApplicationMessageReceived?.Invoke(e);
			}
			catch (Exception obj)
			{
				this.ErrorHandler?.Invoke(obj);
			}
			return Task.CompletedTask;
		}
	}
}
